.include _hwdefs.asm
.include _clrdefs.asm

.define CursorBlinkTicks 20

.org SYSROM
    lds stack
    ldv interrupt
    ldp screen.char

    jss clearscreen

    lda 0
    sta *cursorTimer

    {
        idi
            lda 1
            sta *io.timer
            hlt
            jss handleKeys
            jss blinkCursorTick
        ien
    jpr }

    ;----------

    FUNC / { / irt
        interrupt:
        ;stp *inttempp
        ;ldp s / stp *inttemps
        ;lds intstack
        ;psh f / psh a / psh b / psh c / psh q

        run

        ;pop q / pop c / pop b / pop a / pop f
        ;ldp *inttemps / lds P
        ;ldp *inttempp
    jpr }

    FUNC handleKeys:
        lda *keyboard.queue
        jpz {
            jss keypressed
            jpr handleKeys
        }
    rts

    FUNC blinkCursorTick:
        lda *cursorTimer
        jnz {
            ldp *screenPos
            ldc ph / ldb pl / adc $04 / ldp cb ; get color addr from screen pos
            ;lda *p / xor $80 / sta *p ; toggle highlight blinkCursorTick
            lda *p /xor $03 / sta *p ; toggle black/white

            lda CursorBlinkTicks
        }
        dec a
        sta *cursorTimer
    rts

    FUNC numshifts:         ")!@#$%^&*("
    FUNC keys_2430:         ";=,.-/`"
    FUNC keys_2430_shift:   ":+<>_?~"
    FUNC keys_6063:         "[\\]'"
    FUNC keys_6063_shift:   "{|}\""
    FUNC keys_numpad:       "0123456789*+\n-./"
    FUNC keys_numpad_shift: "0123456789*+\n_.?"

    FUNC keypressed: ; key in a
        ldb a

        ; check for shift
        and $7F
        cmp $10 / jpz keyShift / cmp $14 / jnz keyNoShift
            keyShift:
                lda b / and $80 / shr 7 / sta *shiftDown
                rts
        keyNoShift:

        lda b
        and $80
        jnz { / rts / }

        lda b
        and $7F
        ; ldp *screenPos / sta *p++ / stp *screenPos
        ; jss printhex / lda b
        cmp "A" / jlt { / cmp "Z" / jgt { ; leter
            ldb *shiftDown / jnz {
                add $20
            }
            jss printchar
            rts
        } / }
        cmp "0" / jlt { / cmp "9" / jgt { ; number
            ldb *shiftDown / jpz {
                sub "0" / ldb a / ldp numshifts / adp b
                lda *p
            }
            jss printchar
            rts
        } / }
        ldp keys_2430 / ldq keys_2430_shift / ldb 24 / ldc 30 / jss printcharblock ; symbols
        ldp keys_6063 / ldq keys_6063_shift / ldb 60 / ldc 63 / jss printcharblock
        ldp keys_numpad / ldq keys_numpad_shift / ldb 96 / ldc 111 / jss printcharblock
        cmp 13 / jnz { ; newline
            jss clearCursor
            ldp *screenPos
            ldb pl / ldc ph
            lda b / and $C0 / ldb a
            ldp cb
            adp $40
            stp *screenPos
            jss updateMoveScreen
            rts
        }
        cmp 9 / jnz { ; tab
            rts
        }
        cmp 32 / jnz { /lda 32 / jsr printchar / rts / } ; space
        cmp 8 / jnz { ; backspace
            ldc 1 / jss moveback
            rts
        }
        cmp 37 / jnz { ; left
        ldc 0 / jss moveback
            rts
        }
        cmp 37 / jnz { ; left
            ldc 0 / jss moveback
            rts
        }
        cmp 39 / jnz { ; right
            jss clearCursor
            ldp *screenPos
            lda ph /cmp $0B /jnz {
                lda pl / cmp $FF / jnz {
                    rts
                }
            }
            adp 1
            stp *screenPos
            rts
        }
        jss printhex
    rts

    FUNC moveforward:
    rts

    FUNC moveback: ; c = delete char (bool)
        jss clearCursor
        ldp *screenPos
        lda ph / cmp $08 / jnz {
            lda pl / tst a / jnz {
                rts
            }
        }
        adp -1
        lda *p / jpz { ; one character
            tst c / jpz {
                lda 8 / sta *p
            }
            stp *screenPos
        jpr | ; blank line
            {
                lda pl / and $3F ; stop at beginning of line
                adp -1
                jpz |
                lda *p
            jpz }
            adp 1
            stp *screenPos
        }
    rts

    FUNC printcharblock:
        cmp b / jlt { / cmp c / jgt {
            ldc *shiftDown / jpz {
                ldp q
            }
            sub b / ldb a / adp b
            lda *p / jss printchar
            pop q / rts
        } / }
    rts

    FUNC clearCursor:
        psh a / psh b / psh c
        ldp *screenPos
        ldc ph / ldb pl / adc $04 / ldp cb ; get highlight addr from screen pos
        ;lda *p / and $7F /sta *p; clear highlight bit
        lda CLR_BLACK / sta *p ; set to black
        lda 0 / sta *cursorTimer
        pop c / pop b / pop a
    rts

    FUNC updateMoveScreen:
        ldp *screenPos
        lda ph
        cmp $0C
        jnz {
            jss moveScreenUp
        }
    rts

    FUNC printchar:
        jss clearCursor
        ldp *screenPos / sta *p++ / stp *screenPos
        jss updateMoveScreen
    rts

    FUNC moveScreenUp:
        ldp (SCREEN+$40)
        ldq (SCREEN)
        ldb $0F / {
            ldc $40 / {
                lda *p++ /sta *q++
                dec c
            jnz }
            dec b
        jnz }
        stq *screenPos
        ldb $00
        ldc $20
        ldp (COLOR+$40*$0F)
        lda $40 / {
            stb *q++
            stc *p++
            dec a
        jnz }
    rts

    FUNC printhex:
        ldp *screenPos
        ldb a
        and $F0
        shr 4
        add "0"
        cmp "9" / jle { / add 7 / }
        jss printchar
        lda b
        and $0F
        add "0"
        cmp "9" / jle { / add 7 / }
        jss printchar
        lda 0
        jss printchar
        stp *screenPos
    rts

    FUNC clearscreen:
        ldp screen.char / stp *screenPos
        ldq screen.color
        lda $00 ; blank
        ;ldb CLR_WHITE ; white color, no highlight
        ldb CLR_BLACK ; black color, no highlight
        ldc 128 ; 128 * 8 = 4k of each p and q
        {
            sta *p++
            stb *q++
            sta *p++
            stb *q++
            sta *p++
            stb *q++
            sta *p++
            stb *q++
            sta *p++
            stb *q++
            sta *p++
            stb *q++
            sta *p++
            stb *q++
            sta *p++
            stb *q++
            dec c
        jnz }
    rts

.org SYSRAM
    inttempp: word
    inttemps: word
    intstack: byte[(128-4)]
    stack: byte[128]

.org USERRAM
    screenPos: word
    shiftDown: byte
    cursorTimer: byte
